package main
import (
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"project/tools"
	"golang.org/x/crypto/bcrypt"
    "net/http"       
	"strings"
	"strconv"
	"html/template"
)
//设置全局变量 "_db"
var _db *gorm.DB
//设置安全中间件
func SecurityMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Header("X-Content-Type-Options", "nosniff")
        c.Header("X-Frame-Options", "DENY")
        c.Header("X-XSS-Protection", "1; mode=block")
        // 允许从当前源加载所有资源，包括脚本和样式
        c.Header("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self'")
        
        c.Next()
    }
}
//设立拦截中间件
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		if c.Request.URL.Path == "/login" || c.Request.URL.Path == "/register"{
			c.Next()
			return
		}
		//利用Cookie来判断是否登录
		username,err:= c.Cookie("user")
		if username == "" || err != nil {
			c.Redirect(http.StatusFound,"/login")
			c.Abort() //终止后续处理
			return
		}
	}
}
// 密码哈希函数
func HashPassword(password string) ([]byte, error) {
	// 使用bcrypt算法生成哈希，默认成本为14（数值越高越安全但性能越低）
	return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
}
//注册
//注册页面
func ToRegister(c *gin.Context) {
	c.HTML(http.StatusOK,"Register.html",gin.H{})
}
// 注册功能
func Register(c *gin.Context) {
	// 获取参数
	username := strings.TrimSpace(c.PostForm("username"))
	password := strings.TrimSpace(c.PostForm("password"))
	email := strings.TrimSpace(c.PostForm("email"))

	// 判断参数是否为空
	if username == "" || password == "" || email == "" {
		c.HTML(http.StatusBadRequest, "register.html", gin.H{
			"Error": "用户名、密码和邮箱不能为空",
		})
		return
	}

	// 检查用户名是否已存在
	var existingUser tools.User
	if _db.Where("name = ?", username).First(&existingUser); existingUser.Username != "" {
		c.HTML(http.StatusBadRequest, "register.html", gin.H{
			"Error": "用户名已存在",
		})
		return
	}

	// 密码哈希处理
	hashedPassword, err := HashPassword(password)
	if err != nil {
		c.HTML(http.StatusInternalServerError, "register.html", gin.H{
			"Error": "密码处理失败，请重试",
		})
		return
	}

	// 创建user对象（使用哈希后的密码）
	user := tools.User{
		Username: username,
		Password: string(hashedPassword), // 存储哈希值而非明文
		Email:    email,
	}

	// 添加到数据库
	if err := tools.Register(_db, user); err != nil {
		c.HTML(http.StatusInternalServerError, "register.html", gin.H{
			"Error": "注册失败，请稍后重试",
		})
		return
	}
	c.Redirect(http.StatusFound, "/login") // 重定向到login页面
}
//登录
//登录页面
func ToLogin(c *gin.Context) {
	c.HTML(http.StatusOK,"Login.html",gin.H{})
}
//登录功能
func Login(c *gin.Context) {
    // 获取参数
    Username := strings.TrimSpace(c.PostForm("username"))
    Password := strings.TrimSpace(c.PostForm("password"))
    
    // 查询数据库
    var user tools.User
    result := _db.Where("name = ?", Username).First(&user)
    
    // 检查用户是否存在
    if result.Error != nil {
        c.HTML(http.StatusBadRequest, "Login.html", gin.H{
            "Error": "用户名或密码错误",
        })
        return
    }
    
    // 验证密码（使用bcrypt比较哈希值与明文密码）
    err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(Password))
    if err != nil {
        // 密码不匹配
        c.HTML(http.StatusBadRequest, "Login.html", gin.H{
            "Error": "用户名或密码错误",
        })
        return
    }
    
    // 密码验证成功，设置cookie
    c.SetCookie("user", Username, 3600, "/", "localhost", false, false)
    
    // 重定向到主页
    c.Redirect(http.StatusFound, "/index")
}
//获取cookie
func GetCookie(c *gin.Context) string{
	data,err:= c.Cookie("user")
	if err != nil{
		return ""
	}
	return data
}
//登出
func logout(c *gin.Context) {
	c.SetCookie("user", "", -1, "/", "localhost", false, false)
	c.Redirect(http.StatusFound, "/login")//重定向到login页面
}
//重设密码
//跳转页面
func ToReSet (c *gin.Context) {
	c.HTML(http.StatusOK,"ReSet.html",gin.H{})

}
//重设密码
func ReSet(c *gin.Context) {
    // 获取参数并去除首尾空格
    email := strings.TrimSpace(c.PostForm("email"))
    password1 := strings.TrimSpace(c.PostForm("password1"))
    password2 := strings.TrimSpace(c.PostForm("password2"))

    // 校验邮箱格式（简单示例，可使用更复杂正则）
    if !strings.Contains(email, "@") {
        c.HTML(http.StatusBadRequest, "ReSet.html", gin.H{
            "Error": "邮箱格式不正确",
        })
        return
    }

    // 查询用户
    var user tools.User
    result := _db.Where("email = ?", email).First(&user)
    if result.Error != nil {
        c.HTML(http.StatusBadRequest, "ReSet.html", gin.H{
            "Error": "用户不存在",
        })
        return
    }

    // 检查两次密码是否一致
    if password1 != password2 {
        c.HTML(http.StatusBadRequest, "ReSet.html", gin.H{
            "Error": "两次密码不一致",
        })
        return
    }

    // 验证新密码是否与旧密码相同（使用bcrypt验证）
    err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password1))
    if err == nil {
        c.HTML(http.StatusBadRequest, "ReSet.html", gin.H{
            "Error": "新密码与旧密码相同，请使用不同的密码",
        })
        return
    }

    // 密码哈希
    hashedPassword, err := HashPassword(password1)
    if err != nil {
        c.HTML(http.StatusInternalServerError, "ReSet.html", gin.H{
            "Error": "密码处理失败，请重试",
        })
        return
    }

    // 更新数据库中的密码
    result = _db.Model(&user).Update("password", string(hashedPassword))
    if result.Error != nil {
        c.HTML(http.StatusInternalServerError, "ReSet.html", gin.H{
            "Error": "数据库更新失败，请重试",
        })
        return
    }

    // 跳转到登录页并提示成功
    c.HTML(http.StatusOK, "Login.html", gin.H{
        "Success": "密码重置成功，请使用新密码登录",
    })
}
//主页面(全部查询)
func ToIndex(c *gin.Context) {
	c.HTML(http.StatusOK,"Index.html",gin.H{})
}
//添加学生页面
func ToAddStudent(c *gin.Context) {
    c.HTML(http.StatusOK, "AddStudent.html", gin.H{})
}

//添加学生
func AddStudent(c *gin.Context) {
    // 获取参数
    studentID := strings.TrimSpace(c.PostForm("student_id"))
    name := strings.TrimSpace(c.PostForm("name"))
    gender := strings.TrimSpace(c.PostForm("gender"))
    enrollmentYearStr := strings.TrimSpace(c.PostForm("enrollment_year"))
    majorID := strings.TrimSpace(c.PostForm("major_id"))
    classID := strings.TrimSpace(c.PostForm("class_id"))
    parentPhone := strings.TrimSpace(c.PostForm("parent_phone"))
    finalAvgScoreStr := strings.TrimSpace(c.PostForm("final_avg_score"))
    status := strings.TrimSpace(c.PostForm("status"))

    finalAvgScore, err := strconv.ParseFloat(finalAvgScoreStr, 64)
    if err != nil {
        c.HTML(http.StatusBadRequest, "AddStudent.html", gin.H{
            "Error": "期末平均分必须是数字",
        })
        return
    }
// 创建学生对象
    student := tools.Student{
        StudentID:      studentID,
        Name:           name,
        Gender:         gender,
        EnrollmentYear: enrollmentYearStr,
        MajorID:        majorID,
        ClassID:        classID,
        ParentPhone:    parentPhone,
        FinalAvgScore:  finalAvgScore,
        Status:         status,
    }

    // 添加到数据库
    if err := tools.AddStudent(_db, student); err != nil {
        // 检查错误类型并提供更具体的错误信息
        if strings.Contains(err.Error(), "班级ID不存在") {
            c.HTML(http.StatusBadRequest, "AddStudent.html", gin.H{
                "Error": "班级ID不存在，请输入有效的班级ID",
            })
        } else if strings.Contains(err.Error(), "专业ID不存在") {
            c.HTML(http.StatusBadRequest, "AddStudent.html", gin.H{
                "Error": "专业ID不存在，请输入有效的专业ID",
            })
        } else if strings.Contains(err.Error(), "学生ID已存在") {
            c.HTML(http.StatusBadRequest, "AddStudent.html", gin.H{
                "Error": "学生ID已存在，请使用不同的ID",
            })
        } else {
            c.HTML(http.StatusInternalServerError, "AddStudent.html", gin.H{
                "Error": "添加学生失败，请稍后重试",
            })
        }
        return
    }

    // 重定向到学生列表页面
    c.Redirect(http.StatusFound, "/student")
}

//单个查询

//全部查询(student)
func FindStudentsHandler(c *gin.Context) {
    page := c.DefaultQuery("page", "1")
    pageInt, err := strconv.Atoi(page)
    if err != nil {
        pageInt = 1
    }
    pageSize := 10

    students, err := tools.FindStudents(_db, pageInt, pageSize)
    if err != nil {
        c.HTML(http.StatusInternalServerError, "Student.html", gin.H{
            "Error": "查询学生信息失败，请稍后重试",
        })
        return
    }

    c.HTML(http.StatusOK, "Student.html", gin.H{
        "Students": students,
        "Page":     pageInt,
    })
}
//删除学生
// 删除学生
func DeleteStudent(c *gin.Context) {
    studentID := c.Param("student_id")
    if err := tools.DeleteStudent(_db, studentID); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusOK, gin.H{"message": "学生信息删除成功"})
}

// 删除教师
func DeleteTeacher(c *gin.Context) {
    teacherIDStr := c.Param("teacher_id")
    teacherID, err := strconv.Atoi(teacherIDStr)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "无效的教师ID"})
        return
    }
    if err := tools.DeleteTeacher(_db, teacherID); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusOK, gin.H{"message": "教师信息删除成功"})
}

// 删除班级
func DeleteClass(c *gin.Context) {
    classID := c.Param("class_id")
    if err := tools.DeleteClass(_db, classID); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusOK, gin.H{"message": "班级信息删除成功"})
}

// 删除专业
func DeleteMajor(c *gin.Context) {
    majorIDStr := c.Param("major_id")
    majorID, err := strconv.Atoi(majorIDStr)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "无效的专业ID"})
        return
    }
    if err := tools.DeleteMajor(_db, majorID); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusOK, gin.H{"message": "专业信息删除成功"})
}
//修改学生

// 添加班级页面
func ToAddClass(c *gin.Context) {
    c.HTML(http.StatusOK, "AddClass.html", gin.H{})
}

// 添加班级
func AddClass(c *gin.Context) {
    // 获取参数
    classID := strings.TrimSpace(c.PostForm("class_id"))
    studentCountStr := strings.TrimSpace(c.PostForm("student_count"))
    teacherID := strings.TrimSpace(c.PostForm("TeacherID"))
    className := strings.TrimSpace(c.PostForm("class_name"))
    majorIDStr := strings.TrimSpace(c.PostForm("major_id"))

    // 转换学生数量和专业ID
    studentCount, err := strconv.Atoi(studentCountStr)
    if err != nil {
        c.HTML(http.StatusBadRequest, "AddClass.html", gin.H{
            "Error": "学生数量必须是数字",
        })
        return
    }

    majorID, err := strconv.Atoi(majorIDStr)
    if err != nil {
        c.HTML(http.StatusBadRequest, "AddClass.html", gin.H{
            "Error": "专业ID必须是数字",
        })
        return
    }

    // 创建班级对象
    class := tools.Class{
        ClassID:     classID,
        StudentCount: studentCount,
        TeacherID:    teacherID,
        ClassName:    className,
        MajorID:      majorID,
    }

    // 添加到数据库
    if err := tools.AddClass(_db, class); err != nil {
        // 检查错误类型并提供更具体的错误信息
        if strings.Contains(err.Error(), "班级ID已存在") {
            c.HTML(http.StatusBadRequest, "AddClass.html", gin.H{
                "Error": "班级ID已存在，请使用不同的ID",
            })
        } else {
            c.HTML(http.StatusInternalServerError, "AddClass.html", gin.H{
                "Error": "添加班级失败，请稍后重试",
            })
        }
        return
    }

    // 重定向到班级列表页面
    c.Redirect(http.StatusFound, "/class")
}

// 全部查询(Class)
func FindClassesHandler(c *gin.Context) {
    page := c.DefaultQuery("page", "1")
    pageInt, err := strconv.Atoi(page)
    if err != nil {
        pageInt = 1
    }
    pageSize := 10

    classes, err := tools.FindClasses(_db, pageInt, pageSize)
    if err != nil {
        c.HTML(http.StatusInternalServerError, "Class.html", gin.H{
            "Error": "查询班级信息失败，请稍后重试",
        })
        return
    }

    c.HTML(http.StatusOK, "Class.html", gin.H{
        "Classes": classes,
        "Page":    pageInt,
    })
}

// 添加专业页面
func ToAddMajor(c *gin.Context) {
    c.HTML(http.StatusOK, "AddMajor.html", gin.H{})
}

// 添加专业
func AddMajor(c *gin.Context) {
    // 获取参数
    majorIDStr := strings.TrimSpace(c.PostForm("major_id"))
    name := strings.TrimSpace(c.PostForm("name"))

    // 转换专业ID
    majorID, err := strconv.Atoi(majorIDStr)
    if err != nil {
        c.HTML(http.StatusBadRequest, "AddMajor.html", gin.H{
            "Error": "专业ID必须是数字",
        })
        return
    }

    // 创建专业对象
    major := tools.Major{
        MajorID: majorID,
        Name:    name,
    }

    // 添加到数据库
    if err := tools.AddMajor(_db, major); err != nil {
        // 检查错误类型并提供更具体的错误信息
        if strings.Contains(err.Error(), "专业ID已存在") {
            c.HTML(http.StatusBadRequest, "AddMajor.html", gin.H{
                "Error": "专业ID已存在，请使用不同的ID",
            })
        } else {
            c.HTML(http.StatusInternalServerError, "AddMajor.html", gin.H{
                "Error": "添加专业失败，请稍后重试",
            })
        }
        return
    }

    // 重定向到专业列表页面
    c.Redirect(http.StatusFound, "/major")
}
//查看班级学生信息
func FindStudentsByClassHandler(c *gin.Context) {
    classID := c.Param("class_id")

    var students []struct {
        StudentID string
        Name      string
    }
    err := _db.Table("student").
        Select("student_id, name").
        Where("classID = ?", classID).
        Find(&students).Error
    if err != nil {
        c.HTML(http.StatusInternalServerError, "StudentsByClass.html", gin.H{
            "Error": "查询班级学生信息失败，请稍后重试",
        })
        return
    }

    c.HTML(http.StatusOK, "StudentsByClass.html", gin.H{
        "Students": students,
        "ClassID":  classID,
    })
}
// 全部查询(Major)
func FindMajorsHandler(c *gin.Context) {
    page := c.DefaultQuery("page", "1")
    pageInt, err := strconv.Atoi(page)
    if err != nil {
        pageInt = 1
    }
    pageSize := 10

    majors, err := tools.FindMajors(_db, pageInt, pageSize)
    if err != nil {
        c.HTML(http.StatusInternalServerError, "Major.html", gin.H{
            "Error": "查询专业信息失败，请稍后重试",
        })
        return
    }

    c.HTML(http.StatusOK, "Major.html", gin.H{
        "Majors": majors,
        "Page":   pageInt,
    })
}

// 添加教师页面
func ToAddTeacher(c *gin.Context) {
    c.HTML(http.StatusOK, "AddTeacher.html", gin.H{})
}

// 添加教师
func AddTeacher(c *gin.Context) {
    // 获取参数
    teacherIDStr := strings.TrimSpace(c.PostForm("TeacherID"))
    name := strings.TrimSpace(c.PostForm("Name"))

    // 转换教师ID
    teacherID, err := strconv.Atoi(teacherIDStr)
    if err != nil {
        c.HTML(http.StatusBadRequest, "AddTeacher.html", gin.H{
            "Error": "教师ID必须是数字",
        })
        return
    }

    // 创建教师对象
    teacher := tools.Teacher{
        TeacherID: teacherID,
        Name:      name,
    }

    // 添加到数据库
    if err := tools.AddTeacher(_db, teacher); err != nil {
        // 检查错误类型并提供更具体的错误信息
        if strings.Contains(err.Error(), "教师ID已存在") {
            c.HTML(http.StatusBadRequest, "AddTeacher.html", gin.H{
                "Error": "教师ID已存在，请使用不同的ID",
            })
        } else {
            c.HTML(http.StatusInternalServerError, "AddTeacher.html", gin.H{
                "Error": "添加教师失败，请稍后重试",
            })
        }
        return
    }

    // 重定向到教师列表页面
    c.Redirect(http.StatusFound, "/teacher")
}

// 全部查询(Teacher)
func FindTeachersHandler(c *gin.Context) {
    page := c.DefaultQuery("page", "1")
    pageInt, err := strconv.Atoi(page)
    if err != nil {
        pageInt = 1
    }
    pageSize := 10

    teachers, err := tools.FindTeachers(_db, pageInt, pageSize)
    if err != nil {
        c.HTML(http.StatusInternalServerError, "Teacher.html", gin.H{
            "Error": "查询教师信息失败，请稍后重试",
        })
        return
    }

    c.HTML(http.StatusOK, "Teacher.html", gin.H{
        "Teachers": teachers,
        "Page":     pageInt,
    })
}
//主函数
func main(){
	_db = tools.GetDB()
	r := gin.Default()
	// 添加安全中间件
	r.Use(SecurityMiddleware())
    r.Static("js","./templates/js")
	r.Static("/styles", "./templates/css")
	r.SetFuncMap(template.FuncMap{
        "add": func(a, b int) int {
            return a + b
        },
        "sub": func(a, b int) int {
            return a - b
        },
    })

	r.LoadHTMLGlob("views/*")

	//应用拦截器
	public := r.Group("/")
	{
		public.GET("/register",ToRegister)
		public.POST("/register",Register)
		public.GET("/login",ToLogin)
		public.POST("/login",Login)
		public.GET("/reset",ToReSet)
		public.POST("/reset",ReSet)
        public.GET("/logout",logout)

		//这里存放不需要拦截的请求，例如：public.POST("/login",Login)

	}

	private := r.Group("/")
	//启用拦截中间件
	private.Use(AuthMiddleware())
	{
		private.GET("/index",ToIndex)
		private.GET("/student",FindStudentsHandler)
		private.GET("/toadd", ToAddStudent)
		private.POST("/addstudent", AddStudent)
        private.GET("/class",FindClassesHandler)
        private.GET("/toaddclass", ToAddClass)
        private.POST("/addclass", AddClass)
        private.GET("/major", FindMajorsHandler)
        private.GET("/toaddmajor", ToAddMajor)
        private.POST("/addmajor", AddMajor)
        private.GET("/teacher", FindTeachersHandler)
        private.GET("/toaddteacher", ToAddTeacher)
        private.POST("/addteacher", AddTeacher)
        private.DELETE("/student/:student_id", DeleteStudent)
        private.DELETE("/teacher/:teacher_id", DeleteTeacher)
        private.DELETE("/class/:class_id", DeleteClass)
        private.DELETE("/major/:major_id", DeleteMajor)
        private.GET("/stubyclass/:class_id", FindStudentsByClassHandler) 
		//这里存放需要拦截的请求，例如：private.GET("/index",index)
	}
	r.Run()
}